<?php
/**
 * 
 * @todo description of this class
 * 
 * @author Alton Crossley <crossleyframework@nogahidebootstrap.com>
 * @package Crossley Framework
 *  
 * @copyright Copyright (c) 2003-2009, Nogaide BootStrap INC. All rights reserved.
 * @license BSD http://opensource.org/licenses/bsd-license.php
 * @version $Id:$
 * 
 */

class X_Data_Meta_Table implements X_Interface_Titled
{
    /**
     * name of the table this meta data is for
     *
     * @var string
     */
    public $sName;
    /**
     * abrivation for the table
     * 
     * @todo check this against others in the db for ambiguity
     *
     * @var string
     */
    public $sAbbr;
    /**
     * name of the primary key for the table
     *
     * @var string
     */
    public $sPrimaryKey;
    /**
     * database engine used for the table
     *
     * @var string
     */
    public $sEngine;
    /**
     * current autonum value
     *
     * @var int
     */
    public $iAutoIncrementValue;
    /**
     * default character set
     *
     * @var string
     */
    public $sDefaultCharset;
    /**
     * forien key meta object array for this table
     *
     * @var array of X_Data_Meta_Forienkey
     */
    protected $_aForienKeys = array();
    /**
     * forien key meta array - results in instances in $_aForienKeys
     * 
     * @var array 2D array
     */
    protected $_aForienKeyArray = array();
    /**
     * column meta object array
     *
     * @var array of X_Data_Meta_Column
     */
    protected $_aColumns = array();
    
    function __construct()
    {
    	if (count($this->_aForienKeyArray))
    	{
    		$this->setForienKeys($this->_aForienKeyArray);
    		$this->_aForienKeyArray = array();
    	}
    }
    
    /**
     * @return int
     */
    public function getAutoIncrementValue()
    {
        return $this->AutoIncrementValue;
    }
    
    /**
     * @param int $AutoIncrementValue
     */
    public function setAutoIncrementValue($AutoIncrementValue)
    {
        $this->AutoIncrementValue = (int)$AutoIncrementValue;
    }
    
    /**
     * @return string
     */
    public function getDefaultCharset()
    {
        return $this->DefaultCharset;
    }
    
    /**
     * @param string $DefaultCharset
     */
    public function setDefaultCharset($DefaultCharset)
    {
        $this->DefaultCharset = (string)$DefaultCharset;
    }
    
    /**
     * @return string
     */
    public function getEngine()
    {
        return $this->Engine;
    }
    
    /**
     * @param string $Engine
     */
    public function setEngine($Engine)
    {
        $this->Engine = (string)$Engine;
    }


    /**
     * @return array
     */
    public function getColumns()
    {
        return $this->_aColumns;
    }
    
    /**
     * Return a list of column names
     * @return Array
     */
    public function getColumnNames()
    {
    	$aReturn = array();
    	$aColumns = $this->getColumns();

    	foreach ($aColumns as $oColumn)
    	{
    		if (is_array($oColumn))
    		{
    			$aReturn[] = $oColumn['sName'];
    		}
    		else if (is_object($oColumn)) 
    		{
    			$aReturn[] = $oColumn->sName;
    		}
    	}
    	
    	return $aReturn;
    }
    
    /**
     * @param array $aColumns
     * @return X_Data_Meta_Table
     */
    public function setColumns($aColumns)
    {
        foreach ($aColumns as $xColumn)
        {
            if ($xColumn instanceof X_Data_Meta_Column)
            {
                $this->addColumn($xColumn);
            }
            else if (is_array($xColumn))
            {
                $this->addColumn(
                    X_Data_Meta_Column::fromArray($xColumn)
                );
            }
            else
            {
                throw new X_Data_Meta_Exception('attempt to add invalid data as a column');
            }
        }
        return $this;
    }
    /**
     * add a single column object
     *
     * @param X_Data_Meta_Column $oColumn
     */
    public function addColumn(X_Data_Meta_Column $oColumn)
    {
        $this->_aColumns[$oColumn->getName()] = $oColumn;
    }
    
    /**
     * @return array
     */
    public function getForienKeys()
    {
        return $this->_aForienKeys;
    }
    
    /**
     * @param array $aForienKeys
     * @return X_Data_Meta_Table
     */
    public function setForienKeys(Array $aForienKeys)
    {
        foreach ($aForienKeys as $aFKArray)
        {
        	$oFk = X_Data_Meta_Forienkey::fromArray($aFKArray);
            $this->addForienKey(
                $oFk
            );
        }
        return $this;
    }
    /**
     * set forien key information
     * 
     * @param X_Data_Meta_Forienkey $oFk
     */
    public function addForienKey(X_Data_Meta_Forienkey $oFk)
    {
    	
        $this->_aForienKeys[$oFk->getName()] = $oFk;
    }
    
    /**
     * @return string
     */
    public function getPrimaryKey()
    {
        return $this->sPrimaryKey;
    }
    
    /**
     * @param string $sPrimaryKey
     */
    public function setPrimaryKey($sPrimaryKey)
    {
        $this->sPrimaryKey = (string)$sPrimaryKey;
    }
    
    /**
     * @return string
     */
    public function getName()
    {
        return $this->sName;
    }
    
    /**
     * @param string $sTableName
     */
    public function setName($sTableName)
    {
        $this->sName = (string)$sTableName;
    }
    
    /**
     * @return string
     */
    public function getTableNameAbbr()
    {
        return $this->sAbbr;
    }
    
    /**
     * @param string $sTableNameAbbr
     */
    public function setTableNameAbbr($sTableNameAbbr)
    {
        $this->sAbbr = (string)$sTableNameAbbr;
    }

	/**
     * map array for setting attributes form Array values
     *
     * @var array
     */
    static protected $_aArrayMap = array(
        'table_name' => 'sName'
        ,'table_abbreviation' => 'sAbbr'
        ,'pk' => 'sPrimaryKey'
        ,'columns' => 'aColumns'
        ,'fks' => 'aForienKeys'
        ,'engine' => 'sEngine'
        ,'auto_increment' => 'iAutoIncrementValue'
        ,'default_charset' => 'sDefaultCharset'
    );
    

    /**
     * factory to build this class from an array
     * uses __get wrapper to instanciate FK and column objects
     *
     * @param Array $aArray
     * @return X_Data_Meta_Table
     */
    static public function fromArray(Array $aArray)
    {
        $sClass = __CLASS__;
        $oNew = new $sClass();
        
        foreach ($aArray as $sKey => $sValue)
        {
            if (array_key_exists($sKey, self::$_aArrayMap))
            {
                $sAttrName = self::$_aArrayMap[$sKey];
                $oNew->$sAttrName = $sValue;
            }
        }
        
        return $oNew;   
    }
    
    /**
     * public wrapper for __toArray()
     *
     * @return array
     */
    public function toArray()
    {
        return $this->__toArray();
    }
    
    /**
     * convert the current object to an array
     *
     * @return array
     */
    public function __toArray()
    {
        $a = array();
        foreach (self::$_aArrayMap as $sKey => $sValue)
        {
            $a[$skey] = $this->$sValue;
        }
        
        if (!empty($a['columns']) && is_array($a['columns']))
        {
            foreach ($a['columns'] as $sKey => $oColumn)
            {
                $a['columns'][$sKey] = $oColumn->toArray();
            }
        }
        
        if (!empty($a['fks']) && is_array($a['fks']))
        {
            foreach ($a['fks'] as $sKey => $oFk)
            {
                $a['fks'][$sKey] = $oFk->toArray();
            }
        }
        
        return $a;
    }
    
    public function __get($sKey)
    {
        switch (true) {
            // special access
        	case ($sKey == 'aColumns'):
        	    return $this->getColumns();;
        	    break;
        	case ($sKey == 'aForienKeys'):
        	    return $this->getForienKeys();;
        	    break;
        	// allow access to translated properties
        	case (array_key_exists($sKey, self::$_aArrayMap)):
        	    $sAttrName = self::$_aArrayMap[$sKey];
                return $this->$sAttrName;
                break;
        	default:
        		return;
        	break;
        }
                
    }
    
    public function __set($sKey, $xValue)
    {
        switch (true) {
            // special access
        	case ($sKey == 'aColumns'):
        	    $this->setColumns($xValue);;
        	    break; 
        	case ($sKey == 'aForienKeys'):
        	    $this->setForienKeys($xValue);;
        	    break; 
        	// allow access to translated properties
        	case (array_key_exists($sKey, self::$_aArrayMap)):
        	    $sAttrName = self::$_aArrayMap[$sKey];
                $this->$sAttrName = $xValue;
                break;
        	default:
        		return;
        	break;
        }
    }
	/**
	 * @see X_Interface_Titled
	 */
	public function getTitle() {
		return X_String::toTitle($this->getName());
	}

	/**
	 * @see X_Interface_Identifyable
	 */
	public function getId() {
		return $this->getName();
	}
	
	public function toSource($sClassName = null)
	{
		if (empty($sClassName))
		{
			$sClassName = 'XModel_' . X_String::toCapWords($this->sName);			
		}
		
		$sFkObjects = null;
		foreach ($this->_aForienKeys as $oFK)
		{
			$oFK->sTable = $this->sName; 
			if (strlen($sFkObjects)) $sFkObjects .= "\n,";
			$sFkObjects .= X_Array::toSource((array)$oFK);
		}
		
		$sFkObjects = 'array('."\n{$sFkObjects}\n)";
		$sColumnArray = X_Array::toSource($this->_aColumns);
		return "class {$sClassName} extends X_Data_Meta_Table
{
	/**
     * name of the table this meta data is for
     *
     * @var string
     */
    public \$sName = '{$this->sName}';
    /**
     * abrivation for the table
     * 
     * @todo check this against others in the db for ambiguity
     *
     * @var string
     */
    public \$sAbbr = '{$this->sAbbr}';
    /**
     * name of the primary key for the table
     *
     * @var string
     */
    public \$sPrimaryKey = '{$this->sPrimaryKey}';
    /**
     * database engine used for the table
     *
     * @var string
     */
    public \$sEngine = '{$this->sEngine}';
    /**
     * current autonum value
     *
     * @var int
     */
    public \$iAutoIncrementValue = {$this->iAutoIncrementValue};
    /**
     * default character set
     *
     * @var string
     */
    public \$sDefaultCharset = '{$this->sDefaultCharset}';
    /**
     * forien key meta object array for this table
     *
     * @var array of X_Data_Meta_Forienkey
     */
    protected \$_aForienKeyArray = {$sFkObjects};
    /**
     * column meta object array
     *
     * @var array of X_Data_Meta_Column
     */
    protected \$_aColumns = {$sColumnArray};
}
		";
		
	}

}